home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wvnsc926 / wvart.c < prev    next >
C/C++ Source or Header  |  1994-09-21  |  59KB  |  1,751 lines

  1. /*
  2.  *
  3.  * $Id: wvart.c 1.33 1994/09/22 00:09:56 jcooper Exp $
  4.  * $Log: wvart.c $
  5.  * Revision 1.33  1994/09/22  00:09:56  jcooper
  6.  * Check if text is selected before allowing RMB click to copy
  7.  *
  8.  * Revision 1.33  1994/09/19  16:06:27  jcooper
  9.  * Check if text is selected before allowing RMB click to copy
  10.  * 
  11.  * Revision 1.32  1994/09/18  22:48:51  jcooper
  12.  * support for cascading windows
  13.  * 
  14.  * Revision 1.31  1994/09/16  00:53:16  jcooper
  15.  * massive cleanup for 92.6
  16.  * 
  17.  * Revision 1.30  1994/08/24  17:59:26  jcooper
  18.  * misc encoding/decoding changes
  19.  *
  20.  * Revision 1.29  1994/08/11  00:18:04  jcooper
  21.  * added support for article retreive complete message
  22.  *
  23.  * Revision 1.28  1994/08/03  00:54:10  gardnerd
  24.  * Fixed bug with cut to clipboard at 1st and last line of text
  25.  *
  26.  * Revision 1.27  1994/07/27  21:14:38  gardnerd
  27.  * copy to clipboard
  28.  *
  29.  * Revision 1.26  1994/07/12  19:16:13  rushing
  30.  * missing curlies in CloseArtWnd()
  31.  *
  32.  * Revision 1.25  1994/07/01  03:45:53  dumoulin
  33.  * Added the Find Next Unseen and concept of SPACE as a "power key"
  34.  *
  35.  * Revision 1.24  1994/06/30  21:30:22  gardnerd
  36.  * Allow scrolling by pixels instead of characters
  37.  *
  38.  * Revision 1.23  1994/06/23  23:07:13  dumoulin
  39.  * added menu item for Printer Setup
  40.  *
  41.  * Revision 1.22  1994/06/01  19:01:51  gardnerd
  42.  * horizontal scrolling support
  43.  *
  44.  * Revision 1.21  1994/06/01  18:50:49  rushing
  45.  * more f3 bugs
  46.  *
  47.  * Revision 1.20  1994/05/27  01:29:29  rushing
  48.  * unnecessary winundoc.h
  49.  *
  50.  * Revision 1.19  1994/05/23  18:36:00  jcooper
  51.  * new attach code, session [dis]connect
  52.  *
  53.  * Revision 1.18  1994/02/24  21:26:54  jcoop
  54.  * jcoop changes
  55.  *
  56.  * Revision 1.17  1994/01/24  17:41:01  jcoop
  57.  * 90.2 changes
  58.  *
  59.  * Revision 1.16  1994/01/16  12:23:43  jcoop
  60.  * New font/color painting.  no longer use view_art_by_id
  61.  *
  62.  * Revision 1.15  1993/12/08  01:28:38  rushing
  63.  * new version box and cr lf consistency
  64.  * 
  65.  * Revision 1.14  1993/08/25  18:54:36  mbretherton
  66.  * MRB merge, mail & post logging
  67.  *
  68.  *
  69.  * Revision 1.1x  1993/07/21 MBretherton
  70.  *                remove vRef from MRROpenFile (Mac Stuff)
  71.  *
  72.  * Revision 1.13  1993/08/05  20:06:07  jcoop
  73.  * save multiple articles changes by jcoop@oakb2s01.apl.com (John S Cooper)
  74.  *
  75.  * Revision 1.12  1993/07/06  21:09:50  cnolan
  76.  * win32 support
  77.  *
  78.  * Revision 1.11  1993/06/26  00:53:33  rushing
  79.  * warnings
  80.  *
  81.  * Revision 1.10  1993/06/26  00:18:46  rushing
  82.  * warnings
  83.  *
  84.  * Revision 1.9  1993/06/22  16:45:00  bretherton
  85.  * *** empty log message ***
  86.  *
  87.  * Revision 1.xx M Bretherton  Fix
  88.  *               Mail != Forward in terms of underlying mail support  
  89.  * Revision 1.8  1993/06/11  00:11:26  rushing
  90.  * second merge from Matt Bretherton sources
  91.  *
  92.  * Revision 1.7  1993/05/29  03:32:30  rushing
  93.  * threading support
  94.  *
  95.  * Revision 1.6  1993/05/28  18:23:40  rushing
  96.  * fixed far/huge problem in find_art_by_subject
  97.  *
  98.  * Revision 1.5  1993/05/24  23:28:24  rushing
  99.  * header formatting (MRB)
  100.  *
  101.  *
  102.  * Revision 1.4  1993/05/18  22:11:40  rushing
  103.  * smtp support
  104.  *
  105.  * Revision 1.3  1993/05/06  19:43:41  rushing
  106.  * added Re: fix from MB
  107.  *
  108.  * Revision 1.2  1993/03/30  20:08:25  rushing
  109.  * MAPI
  110.  *
  111.  * Revision 1.1  1993/02/16  20:53:50  rushing
  112.  * Initial revision
  113.  *
  114.  *
  115.  */
  116.  
  117. /*---  wvart.c ------------------------------------------- */
  118. /*  This file contains the window procedure for the Article Viewing window
  119.  *  for WinVn.
  120.  */
  121.  
  122. #include <windows.h>
  123. #include <windowsx.h>
  124. #include "wvglob.h"
  125. #include "winvn.h"
  126. #pragma hdrstop
  127. #include <ctype.h>
  128.  
  129. int cursor_to_char_number (int X, int Y,TypDoc *DocPtr,TypBlock far **BlockPtr,TypLine far **LinePtr);
  130. void CloseArtWnd(HWND hWnd, TypDoc *ThisDoc);
  131. void UpdateHighlightedText(TypDoc far *DocPtr, TextSelect far *PreviousPos);
  132. void HighlightText(TypDoc far *DocPtrs);
  133. void CopyTextToClipBoard(TypDoc FAR *DocPtr);
  134. void SetArticleMenus (HWND hWnd, int enable);
  135.   
  136. /************** find_article_geader_subject *************
  137.  *
  138.  *   Amended to ignore Re: in either heading line as part of match
  139.  *   criteria
  140.  *
  141.  *  Note the duplication of Knowledge of the rules of subject header
  142.  *  format with wvheader : GetArticleSubject
  143.  *
  144.  *  Ideally some object containing all knowledge of rules of format
  145.  *  would be a more elegant implementation
  146.  *  Also note heading changes with each find next of same heading
  147.  *  request. Ideally want to maintain first heading in series
  148.  *  allowing a more liberal interpreation of 'same' in same heading
  149.  *
  150.  *                       Matthew Bretherton 2nd March 1993
  151.  *
  152.  ********************************************************/
  153.  
  154. long find_article_by_subject (header_p headers,
  155.                   long artindex,
  156.                   long num_headers)
  157. {
  158.   char far *nextsub ;
  159.   char far *thissub;
  160.  
  161.   thissub = (header_elt(headers,artindex++))->subject;
  162.   if (CompareStringNoCase (thissub, "Re:", 3) == 0) thissub=thissub + 4;
  163.  
  164.   if (artindex >= num_headers) return (-1);
  165.  
  166.   do {
  167.     nextsub = (header_elt(headers,artindex))->subject ;
  168.     if (CompareStringNoCase (nextsub, "Re:", 3) == 0) nextsub=nextsub + 4;
  169.     if (lstrcmpi (nextsub, thissub) == 0)
  170.       return (artindex);        /* return the index */
  171.   } while (artindex++ < num_headers);
  172.  
  173.   return (-1);                  /* not found */
  174. }
  175.  
  176.  
  177. /****************************************************************************
  178.  
  179.     FUNCTION: WinVnArtWndProc(HWND, unsigned, WORD, LONG)
  180.  
  181.     PURPOSE:  Processes messages
  182.  
  183. ****************************************************************************/
  184.  
  185. long WINAPI WinVnArtWndProc (hWnd, message, wParam, lParam)
  186.      HWND hWnd;
  187.      unsigned message;
  188.      WPARAM wParam;
  189.      LPARAM lParam;
  190. {
  191.   PAINTSTRUCT ps;               /* paint structure          */
  192.  
  193.   HDC hDC;                      /* handle to display context */
  194.   RECT myRect;                  /* selection rectangle      */
  195.   TypDoc *ThisDoc;
  196.   TypGroup far *GroupDoc;
  197.   int ih, j;
  198.   int found, X, Y, charnum;
  199.   int CtrlState;
  200.   TypLine far *LinePtr;
  201.   TypBlock far *BlockPtr;
  202.   HANDLE hBlock;
  203.   char mybuf[MAXINTERNALLINE];
  204.   unsigned int Offset;
  205.   char far *textptr;
  206.   int textlen;
  207.   BOOL continueFind;
  208.   TypLineID MyLineID,artindex;
  209.   HANDLE header_handle;
  210.   HANDLE thread_handle;
  211.   header_p headers;
  212.   header_p header;
  213.   long header_num;
  214.      
  215.   for (ih = 0, found = FALSE; !found && ih < MAXARTICLEWNDS; ih++)
  216.     {
  217.       if (ArticleDocs[ih].hDocWnd == hWnd)
  218.     {
  219.       found = TRUE;
  220.       ThisDoc = &(ArticleDocs[ih]);
  221.     }
  222.     }
  223.  
  224.   if (!found)
  225.     {
  226.       ThisDoc = CommDoc;
  227.     }
  228.  
  229.  
  230.   switch (message)
  231.     {
  232.  
  233.     case WM_CREATE:
  234.       NumArticleWnds++;
  235.       SetArticleMenus(hWnd, DISABLE);
  236.       break;
  237.       
  238.     case WM_ACTIVATE:
  239.     case WM_SETFOCUS:
  240.       if (wParam)
  241.     {
  242.       ActiveArticleDoc = ThisDoc;
  243.     }
  244.       /* fall through */
  245.     case WM_SYSCOMMAND:
  246.       return (DefWindowProc (hWnd, message, wParam, lParam));
  247.  
  248.     case WM_SIZE:
  249.       GetClientRect (hWnd, &myRect);
  250.       ThisDoc->ScXWidth = myRect.right;
  251.       ThisDoc->ScYHeight = myRect.bottom;
  252.       ThisDoc->ScYLines = (myRect.bottom - myRect.top - ArtTopSpace) / ArtLineHeight;
  253.       ThisDoc->ScXChars = (myRect.right - myRect.left - ArtSideSpace) / ArtCharWidth;
  254.       break;
  255.  
  256.     case WM_CLOSE:
  257.       ThisDoc->TextSelected = FALSE;
  258.       CloseArtWnd(hWnd, ThisDoc);
  259.       break;
  260.       
  261.     case WM_DESTROY:
  262.       NumArticleWnds--;
  263.       ThisDoc->TextSelected = FALSE;
  264.       ThisDoc->InUse = FALSE;
  265.       ThisDoc->LongestLine = 0;
  266.       ThisDoc->ScXOffset = 0;
  267.       if (ThisDoc == CommDoc)
  268.     {
  269.       CommBusy = FALSE;
  270.       CommDoc = (TypDoc *) NULL;
  271.     }
  272.       /* Clear the pointer in the line for this article in the   */
  273.       /* group  document.  This pointer currently points       */
  274.       /* to the current document, which we are wiping out      */
  275.       /* with the destruction of this window.                  */
  276.  
  277.       if (ThisDoc->ParentDoc)
  278.     {
  279.     LockLine (ThisDoc->ParentDoc->hParentBlock,
  280.           ThisDoc->ParentDoc->ParentOffset,
  281.           ThisDoc->ParentDoc->ParentLineID,
  282.           &BlockPtr, &LinePtr);
  283.  
  284.     GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
  285.  
  286.     header_handle = GroupDoc->header_handle;
  287.     thread_handle = GroupDoc->thread_handle;        
  288.     headers = lock_headers (header_handle,thread_handle);
  289.  
  290.     (header_elt(headers,ThisDoc->LastSeenLineID))->ArtDoc = (TypDoc *) NULL;
  291.     UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  292.     unlock_headers (header_handle, thread_handle);
  293.     }
  294.       /* Clear document                                        */
  295.       FreeDoc (ThisDoc);
  296.  
  297.       /* If there's another article window, make it the active   */
  298.       /* artcile window so we don't create a new one if the      */
  299.       /* New Article flag is FALSE.                              */
  300.  
  301.       for (j = MAXARTICLEWNDS - 1; j >= 0; j--)
  302.     {
  303.       if (ArticleDocs[j].InUse)
  304.         {
  305.           ActiveArticleDoc = &(ArticleDocs[j]);
  306.           break;
  307.         }
  308.     }
  309.       break;
  310.  
  311.     case WM_KEYDOWN:
  312.       /* See if this key should be mapped to a scrolling event
  313.        * for which we have programmed the mouse.  If so,
  314.        * construct the appropriate mouse call and call the mouse code.
  315.        */
  316.  
  317.       if (wParam == VK_F6)
  318.     {
  319.       NextWindow (ThisDoc);
  320.     }
  321.       else 
  322.         if (wParam == VK_SPACE)
  323.          {   
  324.            if (ThisDoc->ActiveLines > (ThisDoc->ScYLines + ThisDoc->TopLineOrd))
  325.             {
  326.              SendMessage (hWnd,(UINT) WM_KEYDOWN, (WPARAM) VK_NEXT, (LPARAM) 0L);
  327.              break; 
  328.             }
  329.            else 
  330.              { 
  331.               if (!(CommBusy && ThisDoc == CommDoc))
  332.                 SendMessage (hWnd,(UINT) WM_COMMAND, (WPARAM) IDM_FIND_NEXT_UNSEEN, (LPARAM) 0L); 
  333.               break;
  334.               }
  335.          }
  336.       else
  337.     {
  338.       CtrlState = GetKeyState (VK_CONTROL) < 0;
  339.       for (j = 0; j < NUMKEYS; j++)
  340.         {
  341.           if (wParam == key2scroll[j].wVirtKey &&
  342.           CtrlState == key2scroll[j].CtlState)
  343.         {
  344.           SendMessage (hWnd, key2scroll[j].iMessage,
  345.                    key2scroll[j].wRequest, 0L);
  346.           break;
  347.         }
  348.         }
  349.     }
  350.  
  351.       break;    
  352.       
  353.      case WM_RBUTTONDOWN:
  354.        if (ThisDoc->TextSelected) {
  355.           CopyTextToClipBoard(ThisDoc);
  356.           SendMessage (hWnd, (UINT) WM_COMMAND, (WPARAM) IDM_DESELECT_ALL, (LPARAM) 0L);  //Un-mark selection
  357.        }
  358.        break;
  359.  
  360.  
  361.     case WM_LBUTTONDOWN: 
  362.     {
  363.       int TempX, TempY;
  364.                  
  365.       if (CommBusy && CommDoc == ThisDoc)
  366.       {
  367.         MessageBox (hWnd, "Please wait until article retrieval is complete before selecting text.", "Please Wait", MB_OK);
  368.       }
  369.       else    
  370.       {
  371.         DragMouseAction = DRAG_SELECT; 
  372.         ThisDoc->TextSelected = FALSE; 
  373.         EnableMenuItem(GetMenu(hWnd),IDM_COPY,MF_GRAYED) ;
  374.         EnableMenuItem(GetMenu(hWnd),IDM_DESELECT_ALL,MF_GRAYED) ;
  375.         X = LOWORD (lParam);
  376.         Y = HIWORD (lParam);
  377.   
  378.         if (X < ArtSideSpace)
  379.         {
  380.           TempX = ArtSideSpace;
  381.         }
  382.         else
  383.         {
  384.           TempX = min(X, (int)ThisDoc->ScXWidth);
  385.         }
  386.   
  387.         if (Y < ArtTopSpace)
  388.         {
  389.           TempY = ArtTopSpace;
  390.         }
  391.         else
  392.         { 
  393.           TempY = min(Y, (int)(ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight));
  394.           if(TempY > (int)(ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * ArtLineHeight))
  395.           {
  396.             TempY = (int)ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * (int)ArtLineHeight;
  397.           }  
  398.         }
  399.   
  400.         ThisDoc->BeginSelect.LineNum = (TempY - ArtTopSpace) / ArtLineHeight + ThisDoc->TopLineOrd;
  401.         ThisDoc->BeginSelect.CharNum = cursor_to_char_number (TempX,TempY,ThisDoc,&BlockPtr,&LinePtr);
  402.         ThisDoc->EndSelect.LineNum = -1; 
  403.         SetRect(&myRect, 0, 0, ThisDoc->ScXWidth, ThisDoc->ScYHeight);   
  404.         InvalidateRect(ThisDoc->hDocWnd, &myRect, FALSE);
  405.         SetCursor(LoadCursor(NULL, IDC_IBEAM));
  406.         SetCapture(hWnd);
  407.       }
  408.     }    
  409.     break;  
  410.               
  411.     case WM_MOUSEMOVE:
  412.     {
  413.       int X, Y, TempX, TempY;
  414.       TextSelect Previous;
  415.       int ScMin, ScMax;
  416.       POINT CursorLocation;
  417.       MSG Message;
  418.       BOOL ScrollText = FALSE;
  419.       void CheckForUpdate();      
  420.                  
  421.       if(DragMouseAction == DRAG_SELECT)
  422.       {  
  423.         ThisDoc->TextSelected = TRUE;
  424.         EnableMenuItem(GetMenu(hWnd),IDM_COPY,MF_ENABLED) ;
  425.         EnableMenuItem(GetMenu(hWnd),IDM_DESELECT_ALL,MF_ENABLED) ;
  426.         X = LOWORD (lParam);
  427.         Y = HIWORD (lParam);
  428.         
  429.         // Check to see if text selection needs to scroll left.
  430.         if((X < 0) && (ThisDoc->ScXOffset > 0))
  431.         { 
  432.           ScrollText = TRUE;
  433.  
  434.           do // keep scrolling until the mouse moves.
  435.           { 
  436.             TempX = ArtSideSpace;
  437.             if (Y < ArtTopSpace)
  438.             {
  439.               TempY = ArtTopSpace;
  440.             }
  441.             else
  442.             {
  443.               TempY = min(Y, (int)(ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight));
  444.               if(TempY > (int)(ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * ArtLineHeight))
  445.               {
  446.                 TempY = (int)ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * (int)ArtLineHeight;
  447.               }  
  448.             }
  449.             
  450.             Previous.LineNum = ThisDoc->EndSelect.LineNum;
  451.             Previous.CharNum = ThisDoc->EndSelect.CharNum;
  452.             SendMessage(ThisDoc->hDocWnd, WM_HSCROLL, SB_LINEUP, 0);
  453.             ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  454.             ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX,TempY,ThisDoc,&BlockPtr,&LinePtr);
  455.             UpdateHighlightedText(ThisDoc, &Previous);                       
  456.             SendMessage(ThisDoc->hDocWnd, WM_PAINT, 0, 0);
  457.             if(PeekMessage(&Message, ThisDoc->hDocWnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE))
  458.               break;
  459.             GetCursorPos(&CursorLocation);
  460.             ScreenToClient(ThisDoc->hDocWnd, &CursorLocation);
  461.           }
  462.           while((X == CursorLocation.x) && (Y == CursorLocation.y) &&
  463.                 (ThisDoc->ScXOffset > 0));
  464.         }
  465.         
  466.         GetScrollRange(ThisDoc->hDocWnd, SB_HORZ, &ScMin, &ScMax);
  467.         // Check to see if text selection needs to scroll right.
  468.         if((X > (int)ThisDoc->ScXWidth) && ((int)ThisDoc->ScXOffset < ScMax))
  469.         { 
  470.           ScrollText = TRUE;
  471.             
  472.           do // keep scrolling until the mouse moves.
  473.           { 
  474.             TempX = ThisDoc->ScXWidth;
  475.             if (Y < ArtTopSpace)
  476.             {
  477.               TempY = ArtTopSpace;
  478.             }
  479.             else
  480.             {
  481.               TempY = min(Y, (int)(ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight));
  482.               if(TempY > (int)(ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * ArtLineHeight))
  483.               {
  484.                 TempY = (int)ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * (int)ArtLineHeight;
  485.               }  
  486.             }
  487.  
  488.             Previous.LineNum = ThisDoc->EndSelect.LineNum;
  489.             Previous.CharNum = ThisDoc->EndSelect.CharNum;
  490.             SendMessage(ThisDoc->hDocWnd, WM_HSCROLL, SB_LINEDOWN, 0);
  491.             ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  492.             ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX,TempY,ThisDoc,&BlockPtr,&LinePtr);
  493.                                     
  494.             UpdateHighlightedText(ThisDoc, &Previous); 
  495.             SendMessage(ThisDoc->hDocWnd, WM_PAINT, 0, 0);
  496.             if(PeekMessage(&Message, ThisDoc->hDocWnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE))
  497.               break;
  498.             GetCursorPos(&CursorLocation);
  499.             ScreenToClient(ThisDoc->hDocWnd, &CursorLocation);
  500.             }
  501.             while((X == CursorLocation.x) && (Y == CursorLocation.y)
  502.                && ((int)ThisDoc->ScXOffset < ScMax));
  503.         }     
  504.  
  505.         // Check to see if text selection needs to scroll up.
  506.         if((Y < 0) && (ThisDoc->TopLineOrd > 0))
  507.         { 
  508.           ScrollText = TRUE;
  509.           
  510.           do // keep scrolling until the mouse moves.
  511.           { 
  512.             TempY = ArtTopSpace;
  513.             if (X < ArtSideSpace)
  514.             {
  515.               TempX = ArtSideSpace;
  516.             }
  517.             else
  518.             {
  519.               TempX = min(X, (int)ThisDoc->ScXWidth);
  520.             }
  521.                           
  522.             Previous.LineNum = ThisDoc->EndSelect.LineNum;
  523.             Previous.CharNum = ThisDoc->EndSelect.CharNum;
  524.             SendMessage(ThisDoc->hDocWnd, WM_VSCROLL, SB_LINEUP, 0);
  525.             ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  526.             ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX,TempY,ThisDoc,&BlockPtr,&LinePtr);
  527.             UpdateHighlightedText(ThisDoc, &Previous);
  528.             SendMessage(ThisDoc->hDocWnd, WM_PAINT, 0, 0);
  529.             if(PeekMessage(&Message, ThisDoc->hDocWnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE))
  530.               break;
  531.             GetCursorPos(&CursorLocation);
  532.             ScreenToClient(ThisDoc->hDocWnd, &CursorLocation); 
  533.           }
  534.           while((X == CursorLocation.x) && (Y == CursorLocation.y)
  535.              && (ThisDoc->TopLineOrd > 0));
  536.         }
  537.         
  538.         GetScrollRange(ThisDoc->hDocWnd, SB_VERT, &ScMin, &ScMax);
  539.         // Check to see if text selection needs to scroll down.
  540.         if((Y > (int)ThisDoc->ScYHeight) && 
  541.           ((int)ThisDoc->TopLineOrd < ScMax))
  542.         {               
  543.           ScrollText = TRUE;
  544.               
  545.           do // keep scrolling until the mouse moves.
  546.           { 
  547.             TempY = ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight;
  548.             if(TempY > (int)(ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * ArtLineHeight))
  549.             {
  550.               TempY = (int)ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * (int)ArtLineHeight;
  551.             }  
  552.             
  553.             if (X < ArtSideSpace)
  554.             {
  555.               TempX = ArtSideSpace;
  556.             }
  557.             else
  558.             {
  559.               TempX = min(X, (int)ThisDoc->ScXWidth);
  560.             }
  561.                           
  562.             Previous.LineNum = ThisDoc->EndSelect.LineNum;
  563.             Previous.CharNum = ThisDoc->EndSelect.CharNum;
  564.             SendMessage(ThisDoc->hDocWnd, WM_VSCROLL, SB_LINEDOWN, 0);
  565.             ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  566.             ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX,TempY,ThisDoc,&BlockPtr,&LinePtr);
  567.             UpdateHighlightedText(ThisDoc, &Previous);
  568.             SendMessage(ThisDoc->hDocWnd, WM_PAINT, 0, 0); 
  569.             if(PeekMessage(&Message, ThisDoc->hDocWnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_NOREMOVE))
  570.               break;
  571.             GetCursorPos(&CursorLocation);
  572.             ScreenToClient(ThisDoc->hDocWnd, &CursorLocation);
  573.           }
  574.           while((X == CursorLocation.x) && (Y == CursorLocation.y)
  575.              && ((int)ThisDoc->TopLineOrd < ScMax));
  576.         }     
  577.         
  578.         if (!ScrollText)
  579.         { 
  580.           if (X < ArtSideSpace)
  581.           {
  582.             TempX = ArtSideSpace;
  583.           }
  584.           else
  585.           {
  586.             TempX = min(X, (int)ThisDoc->ScXWidth);
  587.           }
  588.           if (Y < ArtTopSpace)
  589.           {
  590.             TempY = ArtTopSpace;
  591.           }
  592.           else
  593.           {
  594.             TempY = min(Y, (int)(ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight));
  595.             if(TempY > (int)(ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * ArtLineHeight))
  596.             {
  597.               TempY = (int)ArtTopSpace + ((int)ThisDoc->TotalLines - (int)ThisDoc->TopLineOrd - 1) * (int)ArtLineHeight;
  598.             }  
  599.           }
  600.           
  601.           Previous.LineNum = ThisDoc->EndSelect.LineNum;
  602.           Previous.CharNum = ThisDoc->EndSelect.CharNum;                           
  603.           ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  604.           ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX, TempY, ThisDoc, &BlockPtr, &LinePtr);
  605.           UpdateHighlightedText(ThisDoc, &Previous);
  606.  
  607.         }
  608.         
  609.         if((ThisDoc->EndSelect.LineNum > ThisDoc->BeginSelect.LineNum) ||
  610.           ((ThisDoc->EndSelect.LineNum == ThisDoc->BeginSelect.LineNum) &&
  611.            (ThisDoc->EndSelect.CharNum >= ThisDoc->BeginSelect.CharNum)))
  612.         {
  613.           if(((Previous.LineNum < ThisDoc->BeginSelect.LineNum) ||
  614.              ((Previous.LineNum == ThisDoc->BeginSelect.LineNum) &&
  615.               (Previous.CharNum <= ThisDoc->BeginSelect.CharNum))))
  616.           {
  617.             InvalidateRect(hWnd, NULL, FALSE);
  618.           } 
  619.         }
  620.         else
  621.         {
  622.           if(((Previous.LineNum > ThisDoc->BeginSelect.LineNum) ||
  623.              ((Previous.LineNum == ThisDoc->BeginSelect.LineNum) &&
  624.               (Previous.CharNum >= ThisDoc->BeginSelect.CharNum))))
  625.           {
  626.             InvalidateRect(hWnd, NULL, FALSE);
  627.           } 
  628.         }       
  629.       }
  630.     }  
  631.     break;  
  632.                     
  633.     case WM_LBUTTONUP:
  634.     {
  635.       int TempX, TempY;
  636.       
  637.       if(DragMouseAction == DRAG_SELECT)
  638.       { 
  639.         DragMouseAction = DRAG_NONE; 
  640.         if(ThisDoc->TextSelected == TRUE)
  641.         {
  642.           X = LOWORD (lParam);
  643.           Y = HIWORD (lParam); 
  644.         
  645.           if (X < ArtSideSpace)
  646.           {
  647.             TempX = ArtSideSpace;
  648.           }
  649.           else
  650.           {
  651.             TempX = min(X, (int)ThisDoc->ScXWidth);
  652.           }
  653.           if (Y < ArtTopSpace)
  654.           {
  655.             TempY = ArtTopSpace;
  656.           }
  657.           else
  658.           {
  659.             TempY = min(Y, (int)(ArtTopSpace + (ThisDoc->ScYLines-1) * ArtLineHeight));
  660.           }
  661.  
  662.           ThisDoc->EndSelect.LineNum = (TempY - (int)ArtTopSpace) / (int)ArtLineHeight + ThisDoc->TopLineOrd; 
  663.           ThisDoc->EndSelect.CharNum = cursor_to_char_number (TempX, TempY, ThisDoc, &BlockPtr, &LinePtr);
  664.           InvalidateRect(ThisDoc->hDocWnd, NULL, FALSE);
  665.        }
  666.         SetCursor(LoadCursor(NULL, IDC_ARROW)); 
  667.         ReleaseCapture();  
  668.       }
  669.     }     
  670.     break;  
  671.        
  672.     case WM_LBUTTONDBLCLK:
  673.       X = LOWORD (lParam);
  674.       Y = HIWORD (lParam);
  675.  
  676.       charnum = cursor_to_char_number (X,Y,ThisDoc,&BlockPtr,&LinePtr);
  677.  
  678.       if (charnum >= 0) {
  679.     textlen = ((TypText far *) ((char far *) LinePtr +
  680.                 sizeof (TypLine)))->NameLen;
  681.  
  682.     textptr = (char far *) ((char far *) LinePtr +
  683.                   sizeof (TypLine) + sizeof (TypText) );
  684.  
  685.     if (textlen)
  686.     {                                       /* find a message-id */
  687.       char far *start, far *end;
  688.  
  689.       for (start = textptr + charnum; start >= textptr; start--) 
  690.         if (*start == '<') break;
  691.  
  692.       for (end = textptr + charnum; end < (textptr + textlen); end++) 
  693.         if (*end == '>') break;
  694.  
  695.       if ((start >= textptr) && (end < (textptr + textlen))) {
  696.         sprintf (str, "%.*Fs", (int) ((long) end - (long) start + 1), start);
  697.         LockLine (ThisDoc->ParentDoc->hParentBlock,
  698.                ThisDoc->ParentDoc->ParentOffset,
  699.                ThisDoc->ParentDoc->ParentLineID,
  700.                &BlockPtr, &LinePtr);
  701.         GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
  702.             ViewArticle (ThisDoc->ParentDoc, ThisDoc->LastSeenLineID, REUSE, SHOW, str);
  703.       }
  704.     }
  705.       }
  706.  
  707.       break;
  708.  
  709.     case WM_VSCROLL:
  710.       ScrollIt (ThisDoc, wParam, lParam);
  711.       break;
  712.       
  713.     case WM_HSCROLL:
  714.              HScrollIt (ThisDoc, wParam, lParam);
  715.              break;
  716.  
  717.     case WM_PAINT:
  718.       {
  719.     HANDLE hBlock;
  720.     unsigned int Offset, MyLen;
  721.     int VertLines, HorzChars;
  722.     int EndofDoc = FALSE;
  723.     int RangeHigh, CurPos;
  724.     int lineNum ;
  725.     char far *textptr;
  726.     TypBlock far *BlockPtr;
  727.     TypLine far *LinePtr;
  728.     int MyColorMask = 1, PrevColorMask = MyColorMask;
  729.     BOOL ROT13Mode = GetArticleRot13Mode(hWnd) ;
  730.     RECT aRect;
  731.     TextSelect FAR *Start, *End;
  732.     SIZE extent;
  733.     HBRUSH hSolidBrush;
  734.         
  735.     hDC = BeginPaint (hWnd, &ps);
  736.     SetBkColor (hDC, ArticleBackgroundColor);
  737.         SetTextColor (hDC, ArticleTextColor);
  738.  
  739.     GetClientRect (hWnd, &myRect);
  740.     VertLines = ThisDoc->ScYLines;
  741.     HorzChars = ThisDoc->ScXChars;
  742.     
  743.     // Prepare to highlight text if it has been selected
  744.     if(ThisDoc->TextSelected)
  745.     {
  746.       // check to see if selection is in a forward direction 
  747.       // (i.e. top-to-bottom or left-to-right
  748.       if((ThisDoc->EndSelect.LineNum > ThisDoc->BeginSelect.LineNum) ||
  749.         ((ThisDoc->EndSelect.LineNum == ThisDoc->BeginSelect.LineNum) &&
  750.          (ThisDoc->EndSelect.CharNum >= ThisDoc->BeginSelect.CharNum)))
  751.       { 
  752.         Start = &ThisDoc->BeginSelect;                                              
  753.         End = &ThisDoc->EndSelect;                       
  754.       }
  755.       else
  756.       {
  757.          Start = &ThisDoc->EndSelect;
  758.          End = &ThisDoc->BeginSelect;  
  759.       }
  760.     }           
  761.     
  762.     LockLine (ThisDoc->hCurTopScBlock, ThisDoc->TopScOffset, ThisDoc->TopScLineID,
  763.           &BlockPtr, &LinePtr);
  764.  
  765.     /* Update the scroll bar thumb position.                 */
  766.  
  767.     CurPos = lineNum = ThisDoc->TopLineOrd;
  768.     if (CurPos < 0)
  769.       CurPos = 0;
  770.     RangeHigh = ThisDoc->TotalLines - VertLines;
  771.     if (RangeHigh < 0)
  772.       RangeHigh = 0;  
  773.     SetScrollRange (hWnd, SB_VERT, 0, RangeHigh, FALSE);
  774.     SetScrollPos (hWnd, SB_VERT, CurPos, TRUE);
  775.                                                                 
  776.     RangeHigh = ThisDoc->LongestLine - ThisDoc->ScXChars; 
  777.     if (RangeHigh < 0) 
  778.     {
  779.       RangeHigh = 0;
  780.       ThisDoc->ScXOffset = 0;
  781.     }
  782.     SetScrollRange (hWnd, SB_HORZ, 0, RangeHigh, FALSE);
  783.     SetScrollPos (hWnd, SB_HORZ, ThisDoc->ScXOffset, TRUE);     
  784.     
  785.     
  786.     /* Now paint this stuff on the screen for debugging. */
  787.  
  788.     X = ArtSideSpace - ThisDoc->ScXOffset * (ArtCharWidth+1);
  789.     Y = ArtTopSpace;
  790.  
  791.     if (LinePtr->length != END_OF_BLOCK)
  792.       do
  793.         {
  794.     //    MyLen = LinePtr->length - sizeof (TypLine) - sizeof (int) - 1;
  795.           MyLen = ((TypText far *) ((char far *) LinePtr +
  796.                     sizeof (TypLine)))->NameLen;
  797.           textptr = (char far *) LinePtr + sizeof (TypLine) + sizeof (TypText);
  798.  
  799.           if  (ROT13Mode && ((unsigned)lineNum > ThisDoc->HeaderLines))
  800.           {  /*  within body of artcile take copy of string to
  801.              avoid changing original data */
  802.          strcpy (mybuf, textptr);
  803.          textptr = mybuf ;
  804.          strROT13(textptr) ;
  805.           }
  806.  
  807.           if (isLineQuotation(textptr))
  808.           {  /* prepare to print a quotation Line */
  809.          SelectObject (hDC, hFontArtQuote);
  810.           } else
  811.           {  /* prepare to print a normal line */
  812.          SelectObject (hDC, hFontArtNormal);
  813.           }
  814.          
  815.           /* Now write out the line. */ 
  816.           /* Check to see the line is to be highlighted */
  817.           if((ThisDoc->TextSelected) && (lineNum >= Start->LineNum) &&
  818.              (lineNum <= End->LineNum))  
  819.           {
  820.             if(MyLen != 0)
  821.             { 
  822.               if(Start->LineNum == End->LineNum)
  823.               { /* Only one line contains highlighted text */
  824.                 GetTextExtentPoint(hDC, (LPSTR)textptr, Start->CharNum, &extent);
  825.                 SetRect(&aRect, X, Y, X + extent.cx, Y+ArtLineHeight);
  826.                 ExtTextOut (hDC, X, Y, ETO_OPAQUE, &aRect, textptr,
  827.                             Start->CharNum, (LPINT)NULL);  
  828.                 SetBkColor(hDC, ArticleTextColor);
  829.                 SetTextColor(hDC, ArticleBackgroundColor);
  830.                 aRect.left = aRect.right;
  831.                 GetTextExtentPoint(hDC, (LPSTR)textptr, End->CharNum+1, &extent);
  832.                 aRect.right = X + extent.cx;
  833.                 ExtTextOut (hDC, aRect.left, Y, ETO_OPAQUE, &aRect, 
  834.                             textptr + Start->CharNum, 
  835.                             End->CharNum - Start->CharNum + 1, (LPINT)NULL);
  836.                 aRect.left = aRect.right;
  837.                 GetTextExtentPoint(hDC, (LPSTR) textptr, MyLen, &extent);
  838.                 aRect.right = X + extent.cx;
  839.                 SetBkColor(hDC, ArticleBackgroundColor);
  840.                 SetTextColor(hDC, ArticleTextColor);
  841.                 ExtTextOut (hDC, aRect.left, Y, ETO_OPAQUE, &aRect, 
  842.                             textptr + End->CharNum + 1, MyLen - End->CharNum - 1,
  843.                             (LPINT)NULL);
  844.                 Y += ArtLineHeight;
  845.                 lineNum++;
  846.               }
  847.               else
  848.               {
  849.                 if(lineNum == Start->LineNum)
  850.                 { /* First line of more than one line to highlight */
  851.                   GetTextExtentPoint(hDC, (LPSTR)textptr, Start->CharNum, &extent);
  852.                   SetRect(&aRect, X, Y, X + extent.cx, Y+ArtLineHeight);
  853.                   ExtTextOut(hDC, X, Y, ETO_OPAQUE, &aRect, textptr,
  854.                              Start->CharNum, (LPINT)NULL);  
  855.                   SetBkColor(hDC, ArticleTextColor);
  856.                   SetTextColor(hDC, ArticleBackgroundColor);
  857.                   aRect.left = aRect.right;
  858.                   GetTextExtentPoint(hDC, (LPSTR)textptr, MyLen, &extent);
  859.                   aRect.right = X + extent.cx;
  860.                   ExtTextOut(hDC, aRect.left, Y, ETO_OPAQUE, &aRect,
  861.                              textptr + Start->CharNum, MyLen - Start->CharNum,
  862.                              (LPINT)NULL);
  863.                   SetBkColor(hDC, ArticleBackgroundColor);
  864.                   SetTextColor(hDC, ArticleTextColor);
  865.                 }
  866.                 if((lineNum > Start->LineNum) && (lineNum < End->LineNum))
  867.                 { /* Whole lines to be highlighted */ 
  868.                   GetTextExtentPoint(hDC, (LPSTR)textptr, MyLen, &extent);
  869.                   SetRect(&aRect, X, Y, X + extent.cx, Y+ArtLineHeight);
  870.                   SetBkColor(hDC, ArticleTextColor);
  871.                   SetTextColor(hDC, ArticleBackgroundColor);
  872.                   ExtTextOut (hDC, X, Y, ETO_OPAQUE, &aRect, textptr,
  873.                               MyLen, (LPINT)NULL);                          
  874.                   SetBkColor(hDC, ArticleBackgroundColor);
  875.                   SetTextColor(hDC, ArticleTextColor);
  876.                 }
  877.                 if(lineNum == End->LineNum)
  878.                 { /* Last line to be highlighted */ 
  879.                   SetBkColor(hDC, ArticleTextColor);
  880.                   SetTextColor(hDC, ArticleBackgroundColor);
  881.                   GetTextExtentPoint(hDC, (LPSTR)textptr, End->CharNum + 1, &extent);
  882.                   SetRect(&aRect, X, Y, X + extent.cx, Y+ArtLineHeight);
  883.                   ExtTextOut(hDC, X, Y, ETO_OPAQUE, &aRect, textptr,
  884.                              End->CharNum + 1, (LPINT)NULL);  
  885.                   aRect.left = aRect.right;
  886.                   GetTextExtentPoint(hDC, (LPSTR)textptr, MyLen, &extent);
  887.                   aRect.right = X + extent.cx;
  888.                   SetBkColor(hDC, ArticleBackgroundColor);
  889.                   SetTextColor(hDC, ArticleTextColor);
  890.                   ExtTextOut(hDC, aRect.left, Y, ETO_OPAQUE, &aRect,
  891.                              textptr + End->CharNum + 1, MyLen - End->CharNum - 1,
  892.                              (LPINT)NULL);
  893.                 }
  894.  
  895.                 Y += ArtLineHeight;
  896.                 lineNum++;                    
  897.               
  898.               }    
  899.             }
  900.             else
  901.             { /* Blank Line -- Rectangle for CR/LF */
  902.               SetRect(&aRect, X, Y, X+4, Y+ArtLineHeight);
  903.               hSolidBrush = CreateSolidBrush(ArticleTextColor);
  904.               FillRect(hDC, &aRect, hSolidBrush); 
  905.               DeleteObject((HGDIOBJ)hSolidBrush);
  906.               Y += ArtLineHeight;
  907.               lineNum++;
  908.             }  
  909.           } 
  910.           else
  911.           { /* Line is not highlighted */
  912.             GetTextExtentPoint(hDC, (LPSTR)textptr, MyLen, &extent);
  913.             SetRect (&aRect, X, Y, X + extent.cx, Y+ArtLineHeight);
  914.           
  915.             ExtTextOut (hDC, X, Y, ETO_OPAQUE, &aRect, textptr,
  916.                         MyLen, (LPINT)NULL);       
  917.             aRect.left = aRect.right;
  918.             Y += ArtLineHeight;
  919.             lineNum++ ; 
  920.           }
  921.                                          
  922.         /* Fill in the space to the right of the end of the line *
  923.          * with the article background color                     */                                         
  924.         aRect.left = aRect.right;
  925.         aRect.right = ThisDoc->ScXWidth;               
  926.         hSolidBrush = CreateSolidBrush(ArticleBackgroundColor);
  927.         FillRect(hDC, &aRect, hSolidBrush);
  928.         DeleteObject((HGDIOBJ)hSolidBrush); 
  929.           
  930.         }
  931.       while (--VertLines > 0 && NextLine (&BlockPtr, &LinePtr));  
  932.       
  933.                                                             
  934.     /* We've reached the end of the data to be displayed     */
  935.     /* on this window.  If there's more screen real estate   */
  936.     /* left, just blank it out and blank top space.          */
  937.     SelectObject (hDC, hArticleBackgroundBrush);
  938.     PatBlt (hDC, 0, Y, myRect.right - 1, myRect.bottom - Y, PATCOPY); 
  939.     PatBlt (hDC, 0, 0, myRect.right - 1, ArtTopSpace, PATCOPY); 
  940.     if(ThisDoc->ScXOffset == 0)
  941.     {
  942.       PatBlt (hDC, 0, 0, ArtSideSpace, ThisDoc->ScYHeight, PATCOPY);
  943.     }  
  944.        
  945.     UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  946.     EndPaint (hWnd, &ps);
  947.     break;
  948.       }
  949.  
  950.     case IDM_ARTICLE_RETRIEVE_COMPLETE:
  951.        SetArticleMenus(hWnd, ENABLE);
  952.        break;
  953.  
  954.     case WM_COMMAND:
  955.       switch (LOWORD(wParam))
  956.     {
  957.     case IDM_EXIT: 
  958.      ThisDoc->TextSelected = FALSE;
  959.      CloseArtWnd(hWnd, ThisDoc);
  960.       break;
  961.  
  962.     case IDM_SAVE:
  963.       if (strcmp (SaveArtFileName, ""))
  964.         {
  965.           SaveArtAppend = TRUE;
  966.           MRRWriteDocument (ActiveArticleDoc, sizeof (TypText), SaveArtFileName, SaveArtAppend);
  967.           /* Should the 0 be sizeof(TypText) ? */
  968.           break;
  969.         }
  970.       else
  971.         {
  972.           goto saveas;
  973.         }
  974.  
  975.     case IDM_SAVEAS:
  976.     saveas:;
  977.  
  978.       if (DialogBox (hInst, "WinVnSaveArt", hWnd, lpfnWinVnSaveArtDlg))
  979.         {
  980.           InvalidateRect (hWnd, NULL, TRUE);
  981.         }
  982.       break;
  983.  
  984.     case IDM_PRINT:
  985.         PrintArticle(hWnd,ThisDoc);
  986.  
  987.       break;
  988.             
  989.         case IDM_PRINT_SETUP:
  990.         PrinterSetup(hWnd,PD_PRINTSETUP);
  991.  
  992.       break; 
  993.       
  994.     case IDM_DECODE_ARTICLE: 
  995.       if (TestDecodeBusy(hWnd, "Can't decode this article"))
  996.          break;
  997.       if (CommBusy && CommDoc == ThisDoc)
  998.       {
  999.          MessageBox (hWnd, "Please wait until article retrieval is complete before decoding", "Please Wait", MB_OK);
  1000.          break;
  1001.       }    
  1002.  
  1003.       if (!DialogBoxParam (hInst, "WinVnDecodeArts", hWnd, lpfnWinVnDecodeArtsDlg, 0))
  1004.          InvalidateRect (hWnd, NULL, TRUE);
  1005.       else
  1006.          DecodeDoc (hWnd, ActiveArticleDoc);
  1007.       break;
  1008.               
  1009.     case IDM_SELECT_ALL:
  1010.       EnableMenuItem(GetMenu(hWnd),IDM_COPY,MF_ENABLED) ;
  1011.       EnableMenuItem(GetMenu(hWnd),IDM_DESELECT_ALL,MF_ENABLED) ;
  1012.       ThisDoc->TextSelected = TRUE;
  1013.       ThisDoc->BeginSelect.LineNum = 0;
  1014.       ThisDoc->BeginSelect.CharNum = 0; 
  1015.       ThisDoc->EndSelect.LineNum = ThisDoc->TotalLines - 1;
  1016.       FindLineOrd(ThisDoc, (unsigned)ThisDoc->EndSelect.LineNum, &BlockPtr, &LinePtr);
  1017.       textlen = ((TypText far *) ((char far *) (LinePtr) +
  1018.                  sizeof (TypLine)))->NameLen;
  1019.       ThisDoc->EndSelect.CharNum = textlen - 1;
  1020.       GetClientRect(hWnd, &myRect);
  1021.       InvalidateRect(hWnd, &myRect, FALSE);         
  1022.       break;                                             
  1023.     
  1024.     case IDM_DESELECT_ALL:
  1025.       EnableMenuItem(GetMenu(hWnd),IDM_COPY,MF_GRAYED) ;
  1026.       EnableMenuItem(GetMenu(hWnd),IDM_DESELECT_ALL,MF_GRAYED) ;
  1027.       ThisDoc->TextSelected = FALSE;
  1028.       GetClientRect(hWnd, &myRect);
  1029.       InvalidateRect(hWnd, &myRect, FALSE);         
  1030.       break;                                             
  1031.     
  1032.     case IDM_COPY:
  1033.       CopyTextToClipBoard(ThisDoc);
  1034.       break;                                             
  1035.     
  1036.     case IDM_FIND_NEXT_SAME:
  1037.     case IDM_NEXT_ARTICLE:
  1038.     case IDM_PREV_ARTICLE:
  1039.          case IDM_FIND_NEXT_UNSEEN:
  1040.          
  1041.       if (ThisDoc->ParentDoc)
  1042.         {
  1043.           LockLine (ThisDoc->ParentDoc->hParentBlock,
  1044.             ThisDoc->ParentDoc->ParentOffset,
  1045.             ThisDoc->ParentDoc->ParentLineID,
  1046.             &BlockPtr, &LinePtr);
  1047.  
  1048.           GroupDoc = (TypGroup far *) ((char far *) LinePtr + sizeof (TypLine));
  1049.               
  1050.               if (GroupDoc)
  1051.                {
  1052.                if (LOWORD(wParam) == IDM_FIND_NEXT_UNSEEN) {
  1053.         header_handle = GroupDoc->header_handle;
  1054.         thread_handle = GroupDoc->thread_handle;
  1055.         headers = lock_headers (header_handle,thread_handle);
  1056.         artindex = ThisDoc->LastSeenLineID;
  1057.           header_num = -1; 
  1058.           
  1059.           while ((++artindex < GroupDoc->total_headers) && header_num < 0)
  1060.             {
  1061.                     header = header_elt (headers,artindex);
  1062.                     if (!header->Seen) header_num = artindex;
  1063.                   } 
  1064.  
  1065.         unlock_headers (header_handle, thread_handle); 
  1066.         if (header_num >= 0)
  1067.         {
  1068.           ViewArticle (ThisDoc->ParentDoc, header_num, REUSE, SHOW, NO_ID);
  1069.           AdjustTopScByDoc (ThisDoc->ParentDoc, (unsigned int)header_num);
  1070.         } else MessageBox (hWnd, "No more Unseen articles in this Group", "That's all!", MB_OK);
  1071.           } 
  1072.           else if (LOWORD(wParam) == IDM_FIND_NEXT_SAME) {
  1073.         header_handle = GroupDoc->header_handle;
  1074.         thread_handle = GroupDoc->thread_handle;
  1075.         headers = lock_headers (header_handle,thread_handle);
  1076.  
  1077.         header_num =
  1078.           find_article_by_subject (headers,
  1079.                        ThisDoc->LastSeenLineID,
  1080.                        GroupDoc->total_headers-1);
  1081.  
  1082.         unlock_headers (header_handle, thread_handle); 
  1083.         if (header_num >= 0) {
  1084.           ViewArticle (ThisDoc->ParentDoc, header_num, REUSE, SHOW, NO_ID);
  1085.           AdjustTopScByDoc (ThisDoc->ParentDoc, (unsigned int)header_num);
  1086.         } else MessageBox (hWnd, "No more articles", "That's all!", MB_OK);
  1087.            }
  1088.  
  1089.           else if ((LOWORD(wParam) == IDM_NEXT_ARTICLE)
  1090.             && (ThisDoc->LastSeenLineID < (GroupDoc->total_headers - 1) )) {
  1091.                ViewArticle (ThisDoc->ParentDoc, ThisDoc->LastSeenLineID + 1, REUSE, SHOW, NO_ID);
  1092.                AdjustTopScByDoc (ThisDoc->ParentDoc, (unsigned int)ThisDoc->LastSeenLineID + 1);
  1093.               } else if ((LOWORD(wParam) == IDM_PREV_ARTICLE)
  1094.                    && (ThisDoc->LastSeenLineID > 0 )) {
  1095.                ViewArticle (ThisDoc->ParentDoc, ThisDoc->LastSeenLineID - 1, REUSE, SHOW, NO_ID);
  1096.                AdjustTopScByDoc (ThisDoc->ParentDoc, (unsigned int)ThisDoc->LastSeenLineID - 1);
  1097.               } else MessageBox (hWnd, "No more articles", "That's all!", MB_OK);
  1098.           }
  1099.  
  1100.            else  MessageBox (hWnd, "Sorry--you must have the group window around\n"
  1101.                          "\for me to be able to find the next article",
  1102.                    "Can't find next article", MB_OK);
  1103.                    
  1104.        UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
  1105.        }
  1106.        
  1107.       else
  1108.         MessageBox (hWnd,
  1109.             "That Group's window is gone.  Reopen it.",
  1110.             "Error", MB_OK);
  1111.  
  1112.       break;
  1113.  
  1114.     case IDM_POST:
  1115.       CreatePostingWnd (hWnd, ThisDoc, DOCTYPE_POSTING);
  1116.       break;
  1117.  
  1118.     case IDM_MAIL:
  1119.       (MailCtrl.fnMlWinCreate)(hWnd, ThisDoc, DOCTYPE_MAIL);
  1120.       break;
  1121.  
  1122.     case IDM_FORWARD:
  1123.  
  1124.       (MailCtrl.fnMlForward)(hWnd, ThisDoc);
  1125.       break;
  1126.  
  1127.     case IDM_SEARCH:
  1128.  
  1129.       FindDoc = ThisDoc;                     
  1130.         if (!(FindDoc->SearchStr[0]) && LastArticleTextFind[0]) 
  1131.           strcpy(FindDoc->SearchStr, LastArticleTextFind);
  1132.  
  1133.       if (DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg))
  1134.         {
  1135.           found = DoFind (TRUE);
  1136.           if (!found)
  1137.         {
  1138.           strcpy (mybuf, "\"");
  1139.           strcat (mybuf, FindDoc->SearchStr);
  1140.           strcat (mybuf, "\" not found.");
  1141.           MessageBox (hWnd, mybuf, "Not found", MB_OK);
  1142.         }
  1143.         else
  1144.           strcpy(LastArticleTextFind, FindDoc->SearchStr);
  1145.  
  1146.         }
  1147.  
  1148.       break;
  1149.  
  1150.     case IDM_SEARCH_NEXT:
  1151.  
  1152.       FindDoc = ThisDoc;
  1153.       continueFind = TRUE;
  1154.       if (!FindDoc->SearchStr[0]) {
  1155.          if (!(FindDoc->SearchStr[0]) && LastArticleTextFind[0]) 
  1156.               strcpy(FindDoc->SearchStr, LastArticleTextFind);
  1157.          continueFind = DialogBox (hInst, "WinVnFind", hWnd, lpfnWinVnFindDlg);
  1158.       }
  1159.  
  1160.       if (continueFind && FindDoc->SearchStr[0])
  1161.         {
  1162.           found = DoFind (!FindDoc->hFindBlock && !FindDoc->FindLineID);
  1163.           if (!found)
  1164.         {
  1165.           strcpy (mybuf, "\"");
  1166.           strcat (mybuf, FindDoc->SearchStr);
  1167.           strcat (mybuf, "\" not found.");
  1168.           MessageBox (hWnd, mybuf, "No more occurrences", MB_OK);
  1169.         }
  1170.         }
  1171.       break;
  1172.  
  1173.  
  1174.     case IDM_ROT13:
  1175.        SetArticleRot13Mode(hWnd,GetArticleRot13Mode( hWnd) != TRUE)  ;
  1176.        InvalidateRect (hWnd, NULL, TRUE);
  1177.       break;
  1178.  
  1179.  
  1180.     }
  1181.          
  1182.     break;    
  1183.  
  1184.     default:
  1185.       return (DefWindowProc (hWnd, message, wParam, lParam));
  1186.     }
  1187.   return (0);
  1188. }
  1189.  
  1190. /*------------ CloseArtWnd ------------------------------
  1191.  *
  1192.  *  Make sure this Wnd is not the active Comm window, then destroy it
  1193.  */
  1194. void CloseArtWnd(HWND hWnd, TypDoc *ThisDoc)
  1195. {
  1196.   if (CommBusy && ThisDoc == CommDoc)
  1197.     MessageBox (hWnd,
  1198.         "Please wait until article retrieval is complete",
  1199.         "Cannot close article window", MB_OK|MB_ICONSTOP);
  1200.   else 
  1201.     DestroyWindow (hWnd);
  1202. }
  1203.  
  1204. void 
  1205. SetArticleMailMenu(HWND hWnd)
  1206. {
  1207.     HMENU hMenu, hSubMenu;
  1208.  
  1209.     hMenu = GetMenu (hWnd);
  1210.     hSubMenu = GetSubMenu (hMenu, 4);    // respond menu
  1211.     EnableMenuItem (hSubMenu, IDM_MAIL, MailCtrl.enableMail);
  1212.     EnableMenuItem (hSubMenu, IDM_FORWARD, MailCtrl.enableForward);
  1213. }
  1214.  
  1215. // dis/enable menu items which depend on article being completely retrieved
  1216. void
  1217. SetArticleMenus (HWND hWnd, int enable)
  1218. {
  1219.     HMENU hMenu, hSubMenu;
  1220.     UINT mode;
  1221.     
  1222.     if (enable == ENABLE)    
  1223.         mode = MF_BYCOMMAND|MF_ENABLED;
  1224.     else
  1225.         mode = MF_BYCOMMAND|MF_DISABLED|MF_GRAYED;
  1226.     
  1227.     hMenu = GetMenu (hWnd);
  1228.     hSubMenu = GetSubMenu (hMenu, 0);    // file menu
  1229.     EnableMenuItem (hSubMenu, IDM_SAVE, mode);
  1230.     EnableMenuItem (hSubMenu, IDM_SAVEAS, mode);
  1231.     EnableMenuItem (hSubMenu, IDM_PRINT, mode);
  1232.     EnableMenuItem (hSubMenu, IDM_PRINT_SETUP, mode);
  1233.     EnableMenuItem (hSubMenu, IDM_DECODE_ARTICLE, mode);
  1234.     EnableMenuItem (hSubMenu, IDM_EXIT, mode);
  1235.  
  1236.     hSubMenu = GetSubMenu (hMenu, 1);    // edit menu
  1237.     EnableMenuItem (hSubMenu, IDM_SELECT_ALL, mode);
  1238.  
  1239.     hSubMenu = GetSubMenu (hMenu, 2);    // search menu
  1240.     EnableMenuItem (hSubMenu, IDM_SEARCH, mode);
  1241.     EnableMenuItem (hSubMenu, IDM_SEARCH_NEXT, mode);
  1242.  
  1243.     hSubMenu = GetSubMenu (hMenu, 3);    // view menu
  1244.     EnableMenuItem (hSubMenu, IDM_NEXT_ARTICLE, mode);
  1245.     EnableMenuItem (hSubMenu, IDM_FIND_NEXT_UNSEEN, mode);
  1246.     EnableMenuItem (hSubMenu, IDM_FIND_NEXT_SAME, mode);
  1247.     EnableMenuItem (hSubMenu, IDM_PREV_ARTICLE, mode);
  1248.  
  1249.     hSubMenu = GetSubMenu (hMenu, 4);    // respond menu
  1250.     EnableMenuItem (hSubMenu, IDM_POST, mode);
  1251.     
  1252.     SetArticleMailMenu(hWnd);
  1253. }
  1254.  
  1255. /*------GetArticleRot13Mode-------------------------------
  1256.  *
  1257.  *  Routine to get the this article window Rot mode.
  1258.  *  Note :
  1259.  *     interogation of windows menu state to determine
  1260.  *     ROT13 drawing mode
  1261.  *    
  1262.  *-----------------------------------------------------*/
  1263.        
  1264. BOOL
  1265. GetArticleRot13Mode(HANDLE hWnd)
  1266.  
  1267.  return (GetMenuState(GetMenu(hWnd),IDM_ROT13,NULL) == MF_CHECKED ) ;
  1268. }
  1269.  
  1270. /*------SetArticleRot13Mode-------------------------------
  1271.  *
  1272.  *  Routine to set the this article window into (or out of
  1273.  *  Rot mode).
  1274.  *  Note :
  1275.  *     interogation of windows menu state to determine
  1276.  *     ROT13 drawing mode
  1277.  *     need to invalidate window to force repaint to display
  1278.  *     in new mode
  1279.  *-----------------------------------------------------*/
  1280.        
  1281. void
  1282. SetArticleRot13Mode(HANDLE hWnd,BOOL RotMode)
  1283. {
  1284.   UINT action ;
  1285.  
  1286.   if (RotMode==TRUE) action = MF_CHECKED ;
  1287.   else action = MF_UNCHECKED ;
  1288.  
  1289.   CheckMenuItem( GetMenu(hWnd),IDM_ROT13,action) ;
  1290.  
  1291. }
  1292.  
  1293. /*            strROT13
  1294.  *
  1295.  * change the input string by ROT'ing each character
  1296.  *
  1297.  *
  1298.  */
  1299. void
  1300. strROT13 (char *cstring)
  1301.  
  1302. {
  1303.   char *cptr=cstring ;
  1304.  
  1305.   while (*cptr )
  1306.   {
  1307.       (*cptr++) = chROT13(*cptr);
  1308.  
  1309.   }
  1310. }
  1311.  
  1312. /*            chROT13
  1313.  *
  1314.  * return a new character that is the ROT(ation of) 13 characters
  1315.  * of the input character
  1316.  *
  1317.  *
  1318.  */
  1319. char chROT13(char achar)
  1320. { char newchar ;
  1321.  
  1322.     if (isalpha(achar)) {
  1323.         if ((achar & 31) <= 13) {
  1324.             newchar = achar+13;
  1325.          } else {
  1326.             newchar = achar-13;
  1327.          }
  1328.     } else
  1329.         newchar = achar;
  1330.     
  1331.  return(newchar); 
  1332. }
  1333. /*            strnROT13
  1334.  *
  1335.  * change the input string by ROT'ating each character
  1336.  * for len or end of string (whichever is less)
  1337.  *
  1338.  *
  1339.  */
  1340. void strnROT13(char *cstring, int cstringlen)
  1341. {
  1342.   char *cptr = cstring ;
  1343.   int  clen = cstringlen ;
  1344.  
  1345.   while (*cptr  && clen)
  1346.   {
  1347.       (*cptr) = chROT13(*cptr);
  1348.       cptr++ ;
  1349.       clen-- ;
  1350.   }
  1351.  
  1352.   
  1353.   
  1354.  
  1355.      
  1356. /* UpdateHighlightedText
  1357.  *
  1358.  * This function updates hightlighted text from the previous
  1359.  * position to the current position.
  1360.  *
  1361.  */
  1362.  
  1363. void UpdateHighlightedText(TypDoc far *DocPtr, TextSelect far *PreviousPos)
  1364. {
  1365.    SIZE extent;
  1366.    char far * textptr;
  1367.    int textlen;
  1368.    RECT Rect;
  1369.    int CurrentLineNum;
  1370.    BOOL ChangedSelectionDirection = FALSE;
  1371.    HBRUSH hSolidBrush;
  1372.    HDC hDC;
  1373.    TypBlock far *BlockPtr;
  1374.    TypLine far *LinePtr;
  1375.    TextSelect far *Start, *End, *Temp;
  1376.         
  1377.    hDC = GetDC(DocPtr->hDocWnd);               
  1378.  
  1379.    // check to see if selection is in a forward direction 
  1380.    // (i.e. top-to-bottom or left-to-right
  1381.    if((DocPtr->EndSelect.LineNum > DocPtr->BeginSelect.LineNum) ||
  1382.      ((DocPtr->EndSelect.LineNum == DocPtr->BeginSelect.LineNum) &&
  1383.       (DocPtr->EndSelect.CharNum >= DocPtr->BeginSelect.CharNum)))
  1384.    { 
  1385.      if((PreviousPos->LineNum == -1))
  1386.      {
  1387.        Start = &DocPtr->BeginSelect;                                              
  1388.        if(ChangedSelectionDirection) 
  1389.        {
  1390.          InvalidateRect(DocPtr->hDocWnd, NULL, FALSE);
  1391.        } 
  1392.         
  1393.      }
  1394.      else
  1395.      {  
  1396.        Start = PreviousPos;
  1397.      }  
  1398.      End = &DocPtr->EndSelect;                       
  1399.      
  1400.      // check to see if highlighting or unhighlighting
  1401.      if((End->LineNum > Start->LineNum) ||
  1402.        ((End->LineNum == Start->LineNum) &&
  1403.         (End->CharNum >= Start->CharNum)))
  1404.      {
  1405.        SetBkColor(hDC, ArticleTextColor);
  1406.        SetTextColor(hDC, ArticleBackgroundColor); 
  1407.      }
  1408.      else
  1409.      {
  1410.        SetBkColor(hDC, ArticleBackgroundColor);
  1411.        SetTextColor(hDC, ArticleTextColor); 
  1412.        Temp = Start;
  1413.        Start = End;
  1414.        End = Temp;
  1415.      }       
  1416.    }
  1417.    else
  1418.    {
  1419.  
  1420.      Start = &DocPtr->EndSelect;
  1421.      if((PreviousPos->LineNum == -1))
  1422.      {
  1423.        End = &DocPtr->BeginSelect;                                              
  1424.        if(ChangedSelectionDirection) 
  1425.        {
  1426.          InvalidateRect(DocPtr->hDocWnd, NULL, FALSE); 
  1427.        }  
  1428.      }                                                  
  1429.      else
  1430.      {  
  1431.        End = PreviousPos;  
  1432.      }
  1433.      
  1434.      // check to see if highlighting or unhighlighting
  1435.      if((End->LineNum > Start->LineNum) ||
  1436.        ((End->LineNum == Start->LineNum) &&
  1437.         (End->CharNum >= Start->CharNum)))
  1438.      {
  1439.        SetBkColor(hDC, ArticleTextColor);
  1440.        SetTextColor(hDC, ArticleBackgroundColor);
  1441.      }
  1442.      else       
  1443.      {
  1444.        SetBkColor(hDC, ArticleBackgroundColor);
  1445.        SetTextColor(hDC, ArticleTextColor); 
  1446.        Temp = Start;
  1447.        Start = End;
  1448.        End = Temp;
  1449.      }       
  1450.    }         
  1451.  
  1452.    FindLineOrd(DocPtr, (unsigned)Start->LineNum, &BlockPtr, &LinePtr);
  1453.    textlen = ((TypText far *) ((char far *) (LinePtr) +
  1454.                sizeof (TypLine)))->NameLen; 
  1455.    textptr = (char far *) ((char far *) (LinePtr) + sizeof (TypLine) + sizeof (TypText) );            
  1456.    if (isLineQuotation(textptr))
  1457.    {  /* prepare to print a quotation Line */
  1458.      SelectObject (hDC, hFontArtQuote);
  1459.    }
  1460.    else
  1461.    {  /* prepare to print a normal line */
  1462.      SelectObject (hDC, hFontArtNormal);
  1463.    }
  1464.     
  1465.    GetTextExtentPoint(hDC, (LPSTR)textptr, Start->CharNum, &extent);
  1466.    Rect.top = (int)ArtTopSpace + ((Start->LineNum - (int)DocPtr->TopLineOrd) * (int)ArtLineHeight);
  1467.    Rect.left = extent.cx - ((int)DocPtr->ScXOffset * (ArtCharWidth +1) - ArtSideSpace);
  1468.  
  1469.    if(Start->LineNum == End->LineNum)
  1470.    {
  1471.      GetTextExtentPoint(hDC, (LPSTR)textptr, End->CharNum +1, &extent);
  1472.      Rect.bottom = Rect.top + ArtLineHeight;
  1473.      Rect.right = extent.cx - ((int)DocPtr->ScXOffset * (ArtCharWidth +1) - ArtSideSpace);
  1474.    
  1475.      if(textlen != 0)
  1476.      {
  1477.        ExtTextOut(hDC, Rect.left, Rect.top, ETO_OPAQUE, &Rect, 
  1478.           textptr + Start->CharNum, End->CharNum - Start->CharNum +1, (LPINT)NULL);
  1479.      }
  1480.      else
  1481.      {
  1482.        Rect.right = Rect.left +4;
  1483.        hSolidBrush = CreateSolidBrush(GetBkColor(hDC));
  1484.        FillRect(hDC, &Rect, hSolidBrush);  /* Rectangle used to represent CR/LF */
  1485.        DeleteObject((HGDIOBJ)hSolidBrush);      
  1486.      }     
  1487.     
  1488.      ReleaseDC(DocPtr->hDocWnd, hDC);
  1489.    }
  1490.    else
  1491.    {
  1492.      GetTextExtentPoint(hDC, (LPSTR)textptr, textlen, &extent);
  1493.      Rect.bottom = Rect.top + ArtLineHeight;
  1494.      Rect.right = extent.cx - ((int)DocPtr->ScXOffset * (ArtCharWidth +1) - ArtSideSpace);
  1495.    
  1496.      if(textlen != 0)
  1497.      {
  1498.        ExtTextOut(hDC, Rect.left, Rect.top, ETO_OPAQUE, &Rect, 
  1499.           textptr + Start->CharNum, textlen - Start->CharNum, (LPINT)NULL);
  1500.      }
  1501.      else
  1502.      {
  1503.        Rect.right = Rect.left +4;
  1504.        hSolidBrush = CreateSolidBrush(GetBkColor(hDC));
  1505.        FillRect(hDC, &Rect, hSolidBrush);  /* Rectangle used to represent CR/LF */
  1506.        DeleteObject((HGDIOBJ)hSolidBrush);      
  1507.      }     
  1508.     
  1509.      
  1510.      CurrentLineNum = Start->LineNum + 1;
  1511.      
  1512.      while(CurrentLineNum < End->LineNum) 
  1513.      {             
  1514.        NextLine(&BlockPtr, &LinePtr);
  1515.        textlen = ((TypText far *) ((char far *) (LinePtr) +
  1516.                  sizeof (TypLine)))->NameLen; 
  1517.        textptr = (char far *) ((char far *) (LinePtr) + sizeof (TypLine) + sizeof (TypText) );            
  1518.        if (isLineQuotation(textptr))
  1519.        {  /* prepare to print a quotation Line */
  1520.          SelectObject (hDC, hFontArtQuote);
  1521.        }
  1522.        else
  1523.        {  /* prepare to print a normal line */
  1524.          SelectObject (hDC, hFontArtNormal);
  1525.        } 
  1526.        
  1527.        Rect.top = (int)ArtTopSpace + ((CurrentLineNum - (int)DocPtr->TopLineOrd) * (int)ArtLineHeight);
  1528.        Rect.left = ArtSideSpace - (int)DocPtr->ScXOffset * (ArtCharWidth +1);
  1529.        GetTextExtentPoint(hDC, (LPSTR)textptr, textlen, &extent);
  1530.        Rect.bottom = Rect.top + ArtLineHeight;
  1531.        Rect.right = extent.cx - ((int)DocPtr->ScXOffset * (ArtCharWidth +1) - ArtSideSpace);
  1532.        
  1533.        if(textlen != 0)
  1534.        {
  1535.          ExtTextOut(hDC, Rect.left, Rect.top, ETO_OPAQUE, &Rect, 
  1536.                     textptr, textlen, (LPINT)NULL);
  1537.        }
  1538.        else
  1539.        {
  1540.          Rect.right = Rect.left +4;
  1541.          hSolidBrush = CreateSolidBrush(GetBkColor(hDC));
  1542.          FillRect(hDC, &Rect, hSolidBrush);  /* Rectangle used to represent CR/LF */
  1543.          DeleteObject((HGDIOBJ)hSolidBrush);      
  1544.        }     
  1545.                   
  1546.        CurrentLineNum++;
  1547.        
  1548.      }             
  1549.      
  1550.      NextLine(&BlockPtr, &LinePtr);
  1551.      textlen = ((TypText far *) ((char far *) (LinePtr) +
  1552.                sizeof (TypLine)))->NameLen; 
  1553.      textptr = (char far *) ((char far *) (LinePtr) + sizeof (TypLine) + sizeof (TypText) );            
  1554.      if (isLineQuotation(textptr))
  1555.      {  /* prepare to print a quotation Line */
  1556.        SelectObject (hDC, hFontArtQuote);
  1557.      }
  1558.      else
  1559.      {  /* prepare to print a normal line */
  1560.        SelectObject (hDC, hFontArtNormal);
  1561.      } 
  1562.     
  1563.      Rect.top = (int)ArtTopSpace + ((CurrentLineNum - (int)DocPtr->TopLineOrd) * (int)ArtLineHeight);
  1564.      Rect.left = ArtSideSpace - (int)DocPtr->ScXOffset * (ArtCharWidth +1);
  1565.      GetTextExtentPoint(hDC, (LPSTR)textptr, End->CharNum + 1, &extent);
  1566.      Rect.bottom = Rect.top + ArtLineHeight;
  1567.      Rect.right = extent.cx - ((int)DocPtr->ScXOffset * (ArtCharWidth +1) - ArtSideSpace);
  1568.        
  1569.      if(textlen != 0)
  1570.      {
  1571.        ExtTextOut(hDC, Rect.left, Rect.top, ETO_OPAQUE, &Rect, 
  1572.                   textptr, End->CharNum + 1, (LPINT)NULL);
  1573.      }
  1574.      else
  1575.      {
  1576.        Rect.right = Rect.left +4;
  1577.        hSolidBrush = CreateSolidBrush(GetBkColor(hDC));
  1578.        FillRect(hDC, &Rect, hSolidBrush); /* Rectangle used to represent CR/LF */
  1579.        DeleteObject((HGDIOBJ)hSolidBrush);      
  1580.      }     
  1581.  
  1582.   }  
  1583.                                       
  1584.   ReleaseDC(DocPtr->hDocWnd, hDC);     
  1585.   
  1586. }   
  1587.    
  1588.  
  1589. void CopyTextToClipBoard(TypDoc FAR *DocPtr)   
  1590. {  
  1591.   TextSelect *Start, *End;
  1592.   TypBlock FAR *BlockPtr;
  1593.   TypLine FAR *LinePtr;
  1594.   int CurrentLineNum;
  1595.   int j;
  1596.   int textlen;
  1597.   char FAR *textptr;
  1598.  
  1599.   HGLOBAL hGlobalMemory;
  1600.   char FAR *GlobalMemoryPtr;           
  1601.   DWORD SelectedTextLength = 0;
  1602.       
  1603.   /* Check to see if selection is in a forward direction.           *
  1604.    * Start should always point to first selected position           *
  1605.    * when the document is seen from top-to-bottom and               *
  1606.    * left-to-right.                                                 */
  1607.   if((DocPtr->EndSelect.LineNum > DocPtr->BeginSelect.LineNum) ||
  1608.     ((DocPtr->EndSelect.LineNum == DocPtr->BeginSelect.LineNum) &&
  1609.      (DocPtr->EndSelect.CharNum >= DocPtr->BeginSelect.CharNum)))
  1610.   { 
  1611.     Start = &DocPtr->BeginSelect;                                              
  1612.     End = &DocPtr->EndSelect;                       
  1613.   }
  1614.   else
  1615.   {
  1616.     Start = &DocPtr->EndSelect;
  1617.     End = &DocPtr->BeginSelect;  
  1618.   }         
  1619.  
  1620.   /*Calculate the number of bytes to be moved to the clipboard.     */
  1621.   CurrentLineNum = Start->LineNum;
  1622.   FindLineOrd(DocPtr, (unsigned)CurrentLineNum, &BlockPtr, &LinePtr);
  1623.   textlen = ((TypText far *) ((char far *) (LinePtr) +
  1624.               sizeof (TypLine)))->NameLen;
  1625.       
  1626.   if(Start->LineNum == End->LineNum)                  
  1627.   {
  1628.     /* Text is selected on only one line.                           */
  1629.     SelectedTextLength = End->CharNum - Start->CharNum + 1;
  1630.   }
  1631.   else
  1632.   {
  1633.     /* Length of the first line. The 2 is for CR/LF.                */
  1634.     SelectedTextLength = textlen - Start->CharNum + 2;
  1635.                  
  1636.     NextLine(&BlockPtr, &LinePtr);
  1637.     CurrentLineNum++;
  1638.         
  1639.     /* Add in the lengths of all whole lines selected               */ 
  1640.     while(CurrentLineNum < End->LineNum)
  1641.     {
  1642.        textlen = ((TypText far *) ((char far *) (LinePtr) +
  1643.                   sizeof (TypLine)))->NameLen;
  1644.          
  1645.        SelectedTextLength += textlen + 2;
  1646.        /* The 2 is for CR/LF.                                       */
  1647.          
  1648.        NextLine(&BlockPtr, &LinePtr);
  1649.        CurrentLineNum++;
  1650.     }
  1651.         
  1652.     /* Add in the length of the last line selected.                 */ 
  1653.     textlen = ((TypText far *) ((char far *) (LinePtr) +
  1654.                sizeof (TypLine)))->NameLen;
  1655.     if(textlen != 0)
  1656.     {
  1657.        SelectedTextLength += End->CharNum + 1; 
  1658.     }
  1659.     else
  1660.     {
  1661.        SelectedTextLength += 2;
  1662.        /* The 2 is for CR/LF.                                       */
  1663.     }    
  1664.   }                            
  1665.        
  1666.   /* Allocate memory and move selected text to clipboard.           *
  1667.    * The 1 is for NULL string termination.                          */
  1668.   hGlobalMemory = GlobalAlloc(GHND, SelectedTextLength + 1);
  1669.   if(hGlobalMemory)
  1670.   {
  1671.     GlobalMemoryPtr = GlobalLock(hGlobalMemory);
  1672.     CurrentLineNum = Start->LineNum;
  1673.     FindLineOrd(DocPtr, (unsigned)CurrentLineNum, &BlockPtr, &LinePtr);
  1674.     textlen = ((TypText far *) ((char far *) (LinePtr) +
  1675.                sizeof (TypLine)))->NameLen;
  1676.     textptr = (char far *) ((char far *) (LinePtr) + sizeof (TypLine) + sizeof (TypText) );            
  1677.     /* Move textptr to the first character selected.                 */
  1678.     textptr += Start->CharNum;
  1679.       
  1680.     if(Start->LineNum == End->LineNum)                  
  1681.     { 
  1682.       /* Copy the text from the only line selected.                   */
  1683.       for(j = 0; j < End->CharNum - Start->CharNum + 1; j++)
  1684.       {
  1685.         *GlobalMemoryPtr++ = *textptr++;
  1686.       }  
  1687.     }
  1688.     else
  1689.     {                          
  1690.       /* Copy the first line and add CR/LF at the end of the line.    */  
  1691.       for(j = 0; j < textlen - Start->CharNum; j++)
  1692.       {
  1693.         *GlobalMemoryPtr++ = *textptr++;
  1694.       }  
  1695.       *GlobalMemoryPtr++ = '\r';
  1696.       *GlobalMemoryPtr++ = '\n';
  1697.       NextLine(&BlockPtr, &LinePtr);
  1698.       CurrentLineNum++;
  1699.       /* Copy all whole lines selected add add CR/LF at the end       *
  1700.       * of each line.                                                */
  1701.       while(CurrentLineNum < End->LineNum)
  1702.       {
  1703.          textlen = ((TypText far *) ((char far *) (LinePtr) +
  1704.                     sizeof (TypLine)))->NameLen;
  1705.          textptr = (char far *) ((char far *) (LinePtr) + 
  1706.                     sizeof (TypLine) + sizeof (TypText) );
  1707.          for(j = 0; j < textlen; j++)
  1708.          {
  1709.            *GlobalMemoryPtr++ = *textptr++;
  1710.          }  
  1711.          *GlobalMemoryPtr++ = '\r';
  1712.          *GlobalMemoryPtr++ = '\n';
  1713.         
  1714.          NextLine(&BlockPtr, &LinePtr);
  1715.          CurrentLineNum++;
  1716.       }
  1717.       /* Copy the last line selected                                  */
  1718.       textlen = ((TypText far *) ((char far *) (LinePtr) +
  1719.                  sizeof (TypLine)))->NameLen;
  1720.       textptr = (char far *) ((char far *) (LinePtr) + sizeof (TypLine) + sizeof (TypText) );
  1721.       if(textlen != 0)
  1722.       {
  1723.         for(j = 0; j < End->CharNum + 1; j++)
  1724.         {
  1725.           *GlobalMemoryPtr++ = *textptr++;
  1726.         }  
  1727.       }
  1728.       else
  1729.       {
  1730.         *GlobalMemoryPtr++ = '\r';
  1731.         *GlobalMemoryPtr++ = '\n';
  1732.       }                                 
  1733.     }                                        
  1734.       
  1735.     GlobalUnlock(hGlobalMemory); 
  1736.     OpenClipboard(DocPtr->hDocWnd); 
  1737.     EmptyClipboard();
  1738.       
  1739.     SetClipboardData(CF_TEXT, hGlobalMemory);
  1740.     CloseClipboard();
  1741.   }
  1742.   else
  1743.   {
  1744.     MessageBox(DocPtr->hDocWnd, "Not enough memory to copy selected text.", "Out Of Memory", MB_OK);
  1745.   }
  1746.  
  1747. }     
  1748.    
  1749.